#include "stdafx.h"
#include "Entity.h"


Entity::Entity() : m_Models(NULL), m_NumTextures(0), m_Textures(NULL), m_NumModel(0), Name(NULL), m_Shader(NULL),
m_Position(Vector3(0, 0, 0)), m_Rotate(Vector3(0, 0, 0)), m_Scale(Vector3(1, 1, 1))
{
}

Vector3 Entity::getProperties(int index)
{
	switch (index)
	{
	case 0:
	{
			  return m_Position;
	}
		break;
	case 1:
	{
			  return m_Scale;
	}
		break;
	case 2:
	{
			  return m_Rotate;
	}
		break;
	default:
		return Vector3();
		break;
	}
}


void Entity::setProperties(int index, Vector3 value)
{
	switch (index)
	{
	case 0:
		{
			m_Position = value;
			for (int i = 0; i < m_NumModel; i++)
				m_Models[i]->m_Position = value;
		}
		break;
	case 1:
		{
			m_Scale = value;
			for (int i = 0; i < m_NumModel; i++)
				m_Models[i]->m_Scale = value;
		}
		break;
	case 2:
		{
			m_Rotate = value;
			for (int i = 0; i < m_NumModel; i++)
				m_Models[i]->m_Rotate = value;
		}
		break;
	default:
		break;
	}
}

void Entity::SetPostion(Vector3 pos)
{
	for (int i = 0; i < m_NumModel; i++)
		m_Models[i]->m_Position = pos;
	m_Position = pos;
}

void Entity::SetScale(Vector3 scale)
{
	m_Scale = scale;
	for (int i = 0; i < m_NumModel; i++)
		m_Models[i]->m_Scale = scale;
}

Model** Entity::getModels()
{
	return m_Models;
}

Model* Entity::getModels(int index)
{
	if (index < 0 || index >= m_NumModel)
		return NULL;
	return m_Models[index];
}

void Entity::setShader(Shaders* sha)
{
	if (m_Shader != NULL)
		delete m_Shader;
	m_Shader = new Shaders(*sha);
}

Shaders* Entity::getShader()
{
	return m_Shader;
}

Texture** Entity::getTextures()
{
	return m_Textures;
}

Texture* Entity::getTextures(int index)
{
	if (index < 0 || index >= m_NumTextures)
		return NULL;
	return m_Textures[index];
}

Entity::~Entity()
{
	Delete_Array_Pointer(m_Models, m_NumModel);
	Delete_Array_Pointer(m_Textures, m_NumTextures);
	Delete(m_Shader);
	Delete_Array(Name);
	//Delete_Array(m_Textures);
}

void Entity::InitMesh(unsigned int Index, const aiMesh* paiMesh)
{
	Vertex* Vertices = new Vertex[paiMesh->mNumVertices];
	unsigned short* Indices = new unsigned short[paiMesh->mNumFaces * 3];

	const aiVector3D Zero3D(0.0f, 0.0f, 0.0f);

	for (unsigned int i = 0; i < paiMesh->mNumVertices; i++)
	{
		const aiVector3D* pPos = &(paiMesh->mVertices[i]);
		const aiVector3D* pNormal = &(paiMesh->mNormals[i]);
		const aiVector3D* pTangent = &(paiMesh->mTangents[i]);
		const aiVector3D* pBitangent = &(paiMesh->mBitangents[i]);
		const aiVector3D* pTexCoord = paiMesh->HasTextureCoords(0) ? &(paiMesh->mTextureCoords[0][i]) : &Zero3D;

		Vertices[i].position = Vector3(pPos->x, pPos->y, pPos->z);
		Vertices[i].texcoord = Vector2(pTexCoord->x, pTexCoord->y);
		Vertices[i].normal = -Vector3(pNormal->x, pNormal->y, pNormal->z);
		Vertices[i].tangent = Vector3(pTangent->x, pTangent->y, pTangent->z);
		Vertices[i].bitangent = Vector3(pBitangent->x, pBitangent->y, pBitangent->z);
	}

	for (int i = 0; i < paiMesh->mNumFaces; i++)
	{
		aiFace face = paiMesh->mFaces[i];
		for (int j = 0; j < face.mNumIndices; j++)
		{
			Indices[i * 3 + j] = face.mIndices[j];
		}
	}

	m_Models[Index] = new Model(Vertices, paiMesh->mNumVertices, Indices, paiMesh->mNumFaces * 3);
	m_Models[Index]->setTextureID(paiMesh->mMaterialIndex);
}

string GetName(string file)
{
	string Output;
	for (int i = 0; i < file.length(); i++)
	{
		if (file[i] == '.')
			break;

		Output.push_back(file[i]);
	}
	return Output;
}

bool Entity::InitMaterials(const aiScene* pScene, const std::string& Filename)
{
	// Extract the directory part from the file name
	std::string::size_type SlashIndex = Filename.find_last_of("/");
	std::string Dir;

	if (SlashIndex == std::string::npos) {
		Dir = ".";
	}
	else if (SlashIndex == 0) {
		Dir = "/";
	}
	else {
		Dir = Filename.substr(0, SlashIndex);
	}

	bool Ret = true;

	// Initialize the materials
	for (unsigned int i = 0; i < pScene->mNumMaterials; i++)
	{
		int index = i * 2;
		const aiMaterial* pMaterial = pScene->mMaterials[i];
		if (pMaterial->GetTextureCount(aiTextureType_DIFFUSE) > 0)
		{
			aiString Path;
			if (pMaterial->GetTexture(aiTextureType_DIFFUSE, 0, &Path, NULL, NULL, NULL, NULL, NULL) == AI_SUCCESS)
			{

				std::string FullPath = Dir + "/" + Path.data;
				m_Textures[index] = new Texture();
				m_Textures[index]->Load2DTexture((char*)FullPath.c_str());
				FullPath = Dir + "/" + GetName(Path.data) + "_NRM.tga";
				m_Textures[index + 1] = new Texture();
				m_Textures[index + 1]->Load2DTexture((char*)FullPath.c_str());
			}
		}

		// Load a white texture in case the model does not include its own texture
		if (!m_Textures[index])
		{
			std::string FullPath = "../Resources/Texture/white.tga";
			m_Textures[index] = new Texture();
			m_Textures[index]->Load2DTexture((char*)FullPath.c_str());
		}

		if (!m_Textures[index + 1])
		{
			std::string FullPath = "../Resources/Texture/white.tga";
			m_Textures[index + 1] = new Texture();
			m_Textures[index + 1]->Load2DTexture((char*)FullPath.c_str());
		}
	}

	return Ret;
}

bool Entity::InitFromScene(const aiScene* pScene, const char* filename)
{
	m_NumModel = pScene->mNumMeshes;
	m_Models = new Model*[m_NumModel];

	m_NumTextures = pScene->mNumMaterials * 2;
	m_Textures = new Texture*[m_NumTextures];
	// Initialize the meshes in the scene one by one

	for (unsigned int i = 0; i < m_NumModel; i++) {
		const aiMesh* paiMesh = pScene->mMeshes[i];
		InitMesh(i, paiMesh);
	}


	return InitMaterials(pScene, string(filename));
}

void Entity::draw()
{

}

int Entity::Load_Collada(const char* filename, char* VS, char* FS)
{
	Clear();
	m_Shader = new Shaders();
	m_Shader->Init(VS, FS);

	bool Ret = false;
	Assimp::Importer Importer;

	const aiScene* pScene = Importer.ReadFile(filename,
		aiProcess_GenSmoothNormals |
		aiProcess_Triangulate |
		aiProcess_CalcTangentSpace |
		aiProcess_FlipUVs);

	if (pScene) {
		Ret = InitFromScene(pScene, filename);
	}
	else {
		printf("Error parsing '%s': '%s'\n", filename, Importer.GetErrorString());
	}

	return Ret;
}

void Entity::Clear()
{
	if (m_Models != NULL)
	{
		for (unsigned int i = 0; i < m_NumModel; i++)
		{
			delete[] m_Models[i];
		}
		delete[] m_Models;
	}
}